package com.zys.background.gateway.config;

import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;

/**
 * <p>加上 @RefreshScope 注解可以动态刷新服务列表 DiscoveryClient</p>
 * @apiNote 服务路由配置
 * @author zys
 * @since 2022-11-25
 */
@RefreshScope
@RequiredArgsConstructor
@Configuration(proxyBeanMethods = false)
public class GatewayConfiguration {
  @Value("${spring.application.name}")
  private String serviceName;
  private final DiscoveryClient discoveryClient;

  private static final String LOADBALANCER_PREFIX = "lb://";

  @Bean
  public RouteLocator routeLocator(ConfigurableApplicationContext context) {
    RouteLocatorBuilder routeLocatorBuilder = new RouteLocatorBuilder(context);
    RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
    List<String> services = discoveryClient.getServices();
    services.stream().filter(s -> !s.equals(serviceName))
        .forEach(s -> routes.route(s, r -> r.path(pathPredicateFilter(s)).uri(LOADBALANCER_PREFIX + s)).build());
    return routes.build();
  }

  @Bean
  public CaffeineCacheManager caffeineCacheManager() {
    return new CaffeineCacheManager();
  }

  /**
   * 将服务名转成路径, 如 system-service 转成 /system/**, 每个服务的服务名需要满足 xxx-service 格式(懒得写正则),
   * 且 server.servlet.context-path 为 /xxx
   * @param serviceName 服务名
   * @return /
   */
  public static String pathPredicateFilter(String serviceName) {
    return serviceName.contains("-") ? "/" + serviceName.substring(0, serviceName.indexOf("-")) + "/**" : "";
  }
}
